﻿using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Text;
using Shared.Model;

namespace Shared.Method
{
    public class PortBaseClass
    {
        public const int MAXSIZE = 0xFFFF;
        public static byte[] s_Buffer = new byte[MAXSIZE];

        /// <summary>
        /// 判断端口是否被使用
        /// </summary>
        /// <param name="port"></param>
        /// <returns></returns>
        public static bool IsPortInUse(int port)
        {
            bool inUse = false;

            IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties();
            IPEndPoint[] ipEndPoints = ipProperties.GetActiveTcpListeners();

            foreach (IPEndPoint endPoint in ipEndPoints)
            {
                if (endPoint.Port == port)
                {
                    inUse = true;
                    break;
                }
            }
            return inUse;
        }

        //串口通信接口
        public static bool OpenOrCloseBox(string portName, bool isOpen = true)
        {
            try
            {
                SerialPort serialPort = new SerialPort
                {
                    BaudRate = 9600,
                    PortName = portName,
                    DataBits = 8
                };

                serialPort.Open();

                if (serialPort.IsOpen == false)
                {
                    throw new Exception("未能打开端口");
                }

                if (isOpen)
                    serialPort.Write("OPEN\r\n");//打开屏蔽箱
                else
                    serialPort.Write("CLOSE\r\n");//关闭屏蔽箱
                                                  //byte[] openB = { 0x4F, 0x50, 0x45, 0x4E, 0x0D, 0x0A };
                                                  //serialPort.Write(openB, 0, 6);

                serialPort.Close();
                return true;
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }

        }


        /// <summary>
        /// 获取串口连接
        /// </summary>
        /// <param name="baudRate">比特率</param>
        /// <param name="portName">端口名称</param>
        /// <param name="dataBits">串口位数</param>
        /// <param name="message">返回信息</param>
        /// <returns></returns>
        public static SerialPort GetNewSerialPort(int baudRate, string portName, int dataBits, out string message)
        {
            message = string.Empty;

            if (string.IsNullOrEmpty(portName))
            {
                message = "COM口为空";
                return null;
            }

            try
            {
                SerialPort serial = new SerialPort()
                {
                    BaudRate = baudRate,
                    PortName = portName,
                    DataBits = dataBits,
                    ReadTimeout = 1500
                };

                serial.Open();

                if (serial.IsOpen == false)
                {
                    throw new Exception("串口连接失败");
                }

                return serial;
            }
            catch (Exception ex)
            {
                message = ex.ToString();
                return null;
            }
        }

        /// <summary>
        /// 发送命令，得到输出
        /// </summary>
        /// <param name="serial">串口对象</param>
        /// <param name="sendStr">发送指令</param>
        /// <param name="recvStr">接收字段</param>
        /// <param name="message">返回信息</param>
        /// <param name="waitTimes">等待次数，默认10</param>
        /// <returns></returns>
        public static bool SerialPortSendAndRecv(SerialPort serial, string sendStr, string recvStr, out string message, int waitTimes = 5)
        {
            message = string.Empty;

            if (serial == null || string.IsNullOrEmpty(recvStr)) return false;

            try
            {
                if (serial.IsOpen == false) return false;

                if (string.IsNullOrEmpty(sendStr) == false)
                {
                    serial.Write(sendStr + "\r\n");
                }

                bool canRecv = false;

                for (int i = 0; i < waitTimes; i++)
                {
                    System.Threading.Thread.Sleep(400);

                    if (serial.IsOpen == false) break;
                    message += serial.ReadExisting();

                    if (message.Contains(recvStr)) { canRecv = true; break; }
                }

                return canRecv;
            }
            catch (Exception ex)
            {
                message += ex.ToString();
                serial?.Close();
                return false;
            }
        }

        /// <summary>
        /// 发送命令，得到输出
        /// </summary>
        /// <param name="serial">串口对象</param>
        /// <param name="sendBytes">发送指令</param>
        /// <param name="recvBytes">接收字段</param>
        /// <param name="message">返回信息</param>
        /// <param name="waitTimes">等待次数，默认10</param>
        /// <returns></returns>
        public static byte[] SerialPortSendAndRecv(SerialPort serial, byte[] sendBytes)
        {
            //message = string.Empty;

            if (serial == null || sendBytes == null) return null;

            lock (serial)

                try
                {
                    if (serial.IsOpen == false) return null;

                    if (sendBytes != null)
                    {
                        serial.Write(sendBytes, 0, sendBytes.Length);
                    }

                    System.Threading.Thread.Sleep(300);

                    if (serial.IsOpen == false) return null;
                    int length = serial.Read(s_Buffer, 0, MAXSIZE);

                    if (length == 0) return null;

                    return s_Buffer.Take(length).ToArray();
                }
                catch
                {
                    serial?.Close();
                    return null;
                }
        }

        private static readonly object lockObj = new object();

        public static string ScanControl(SerialPort serial, string portName, byte[] sendCodes, byte[] recvCodes)
        {
            lock (lockObj)
                try
                {
                    string msg = string.Empty;

                    if (serial == null || serial.IsOpen == false) serial.Open();

                    System.Threading.Thread.Sleep(1000);

                    if (serial.IsOpen == false) { return string.Empty; }

                    byte[] recv = null;

                    recv = SerialPortSendAndRecv(serial, sendCodes);

                    if (recv == null) return string.Empty;

                    if (recv.Length == recvCodes.Length && recv.SequenceEqual(recvCodes))
                    {
                        SerialPortSendAndRecv(serial, string.Empty, "\r", out msg, 10);
                        return msg.Trim();
                    }

                    if (recv.Length > recvCodes.Length && recv.Take(recvCodes.Length).ToArray().SequenceEqual(recvCodes))
                    {
                        return Encoding.UTF8.GetString(recv.Skip(recvCodes.Length).ToArray()).Trim();
                    }

                    return string.Empty;

                }
                catch
                {
                    return string.Empty;
                }
        }

        public static byte CalculationChecksum(byte[] input, int offset, int length)
        {
            if (input == null || input.Length == 0 || offset + length > input.Length)
            {
                return 0;
            }

            byte sum = 0;

            for (int i = offset; i < length + offset; i++)
            {
                sum += input[i];
            }

            return sum;

        }

        public static bool PowerOffAndOn(int switchNum,SerialPort serial)
        {
            //get power off struct

            System.Threading.Thread.Sleep(1000);

            SharedData.POWER_OFF_COMMAND[6] = (byte)switchNum;
            SharedData.POWER_OFF_COMMAND[7] = CalculationChecksum(SharedData.POWER_OFF_COMMAND, 0, 7);
            SharedData.POWER_OFF_COMMAND_RECV[6] = (byte)switchNum;
            SharedData.POWER_OFF_COMMAND_RECV[7] = CalculationChecksum(SharedData.POWER_OFF_COMMAND_RECV, 0, 7);


            var recv = SerialPortSendAndRecv(serial, SharedData.POWER_OFF_COMMAND);
            //if (recv.Equals(SharedData.POWER_OFF_COMMAND_RECV) == false) return false;
            if(recv.CompareItems(
                SharedData.POWER_OFF_COMMAND_RECV,
                0,
                SharedData.POWER_OFF_COMMAND_RECV.Length) == false)
            {
                return false;
            }

            System.Threading.Thread.Sleep(2000);

            SharedData.POWER_ON_COMMAND[6] = (byte)switchNum;
            SharedData.POWER_ON_COMMAND[7] = CalculationChecksum(SharedData.POWER_ON_COMMAND, 0, 7);
            SharedData.POWER_ON_COMMAND_RECV[6] = (byte)switchNum;
            SharedData.POWER_ON_COMMAND_RECV[7] = CalculationChecksum(SharedData.POWER_ON_COMMAND_RECV, 0, 7);

            recv = SerialPortSendAndRecv(serial, SharedData.POWER_ON_COMMAND);
            //if (recv.Equals(SharedData.POWER_ON_COMMAND_RECV)==false) return false;

            if(recv.CompareItems(
                SharedData.POWER_ON_COMMAND_RECV,
                0,
                SharedData.POWER_ON_COMMAND_RECV.Length) == false)
            {
                return false;
            }


            return true;
        }

    }
}
